module ub_rd_arbiter (
    input logic clk,
    input logic rst_n,
    ub_rd_req_if.in u_arb_normal_rd_req_if,
    ub_rd_req_if.in u_arb_atomic_rd_req_if,
    ub_rd_req_if.in u_ldma_rd_req_if,
    ub_rd_req_if.out u_gnt_rd_req0_if,
    ub_rd_req_if.out u_gnt_rd_req1_if
);

    // Round-robin arbitration state
    // 3 requesters: 0-ARU normal, 1-Atomic, 2-LDMA
    logic [1:0] last_grant0;
    logic [1:0] last_grant1;

    // Collect all read requests
    logic [2:0] req_vld;
    assign req_vld[0] = u_arb_normal_rd_req_if.vld;
    assign req_vld[1] = u_arb_atomic_rd_req_if.vld;
    assign req_vld[2] = u_ldma_rd_req_if.vld;

    // Grant logic for port 0
    logic [1:0] grant0_sel;
    logic       grant0_vld;

    always_comb begin
        grant0_vld = 1'b0;
        grant0_sel = 2'd0;

        // Round-robin priority based on last_grant0
        case (last_grant0)
            2'd0: begin  // Last grant was ARU normal, try Atomic -> LDMA -> ARU
                if (req_vld[1]) begin
                    grant0_sel = 2'd1;
                    grant0_vld = 1'b1;
                end else if (req_vld[2]) begin
                    grant0_sel = 2'd2;
                    grant0_vld = 1'b1;
                end else if (req_vld[0]) begin
                    grant0_sel = 2'd0;
                    grant0_vld = 1'b1;
                end
            end
            2'd1: begin  // Last grant was Atomic, try LDMA -> ARU -> Atomic
                if (req_vld[2]) begin
                    grant0_sel = 2'd2;
                    grant0_vld = 1'b1;
                end else if (req_vld[0]) begin
                    grant0_sel = 2'd0;
                    grant0_vld = 1'b1;
                end else if (req_vld[1]) begin
                    grant0_sel = 2'd1;
                    grant0_vld = 1'b1;
                end
            end
            2'd2: begin  // Last grant was LDMA, try ARU -> Atomic -> LDMA
                if (req_vld[0]) begin
                    grant0_sel = 2'd0;
                    grant0_vld = 1'b1;
                end else if (req_vld[1]) begin
                    grant0_sel = 2'd1;
                    grant0_vld = 1'b1;
                end else if (req_vld[2]) begin
                    grant0_sel = 2'd2;
                    grant0_vld = 1'b1;
                end
            end
            default: begin
                if (req_vld[0]) begin
                    grant0_sel = 2'd0;
                    grant0_vld = 1'b1;
                end else if (req_vld[1]) begin
                    grant0_sel = 2'd1;
                    grant0_vld = 1'b1;
                end else if (req_vld[2]) begin
                    grant0_sel = 2'd2;
                    grant0_vld = 1'b1;
                end
            end
        endcase
    end

    // Grant logic for port 1 - select from remaining requesters
    logic [2:0] req_vld_remaining;
    logic [1:0] grant1_sel;
    logic       grant1_vld;

    // Mask out the request granted on port 0
    always_comb begin
        req_vld_remaining = req_vld;
        if (grant0_vld) begin
            req_vld_remaining[grant0_sel] = 1'b0;
        end
    end

    always_comb begin
        grant1_vld = 1'b0;
        grant1_sel = 2'd0;

        // Round-robin priority based on last_grant1
        case (last_grant1)
            2'd0: begin  // Last grant was ARU normal, try Atomic -> LDMA -> ARU
                if (req_vld_remaining[1]) begin
                    grant1_sel = 2'd1;
                    grant1_vld = 1'b1;
                end else if (req_vld_remaining[2]) begin
                    grant1_sel = 2'd2;
                    grant1_vld = 1'b1;
                end else if (req_vld_remaining[0]) begin
                    grant1_sel = 2'd0;
                    grant1_vld = 1'b1;
                end
            end
            2'd1: begin  // Last grant was Atomic, try LDMA -> ARU -> Atomic
                if (req_vld_remaining[2]) begin
                    grant1_sel = 2'd2;
                    grant1_vld = 1'b1;
                end else if (req_vld_remaining[0]) begin
                    grant1_sel = 2'd0;
                    grant1_vld = 1'b1;
                end else if (req_vld_remaining[1]) begin
                    grant1_sel = 2'd1;
                    grant1_vld = 1'b1;
                end
            end
            2'd2: begin  // Last grant was LDMA, try ARU -> Atomic -> LDMA
                if (req_vld_remaining[0]) begin
                    grant1_sel = 2'd0;
                    grant1_vld = 1'b1;
                end else if (req_vld_remaining[1]) begin
                    grant1_sel = 2'd1;
                    grant1_vld = 1'b1;
                end else if (req_vld_remaining[2]) begin
                    grant1_sel = 2'd2;
                    grant1_vld = 1'b1;
                end
            end
            default: begin
                if (req_vld_remaining[0]) begin
                    grant1_sel = 2'd0;
                    grant1_vld = 1'b1;
                end else if (req_vld_remaining[1]) begin
                    grant1_sel = 2'd1;
                    grant1_vld = 1'b1;
                end else if (req_vld_remaining[2]) begin
                    grant1_sel = 2'd2;
                    grant1_vld = 1'b1;
                end
            end
        endcase
    end

    // Update last_grant registers
    always_ff @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            last_grant0 <= 2'd0;
            last_grant1 <= 2'd0;
        end else begin
            if (grant0_vld && u_gnt_rd_req0_if.rdy) begin
                last_grant0 <= grant0_sel;
            end
            if (grant1_vld && u_gnt_rd_req1_if.rdy) begin
                last_grant1 <= grant1_sel;
            end
        end
    end

    // Output port 0
    always_comb begin
        u_gnt_rd_req0_if.vld = grant0_vld;
        case (grant0_sel)
            2'd0: begin
                u_gnt_rd_req0_if.ub_addr = u_arb_normal_rd_req_if.ub_addr;
                u_gnt_rd_req0_if.src     = u_arb_normal_rd_req_if.src;
            end
            2'd1: begin
                u_gnt_rd_req0_if.ub_addr = u_arb_atomic_rd_req_if.ub_addr;
                u_gnt_rd_req0_if.src     = u_arb_atomic_rd_req_if.src;
            end
            2'd2: begin
                u_gnt_rd_req0_if.ub_addr = u_ldma_rd_req_if.ub_addr;
                u_gnt_rd_req0_if.src     = u_ldma_rd_req_if.src;
            end
            default: begin
                u_gnt_rd_req0_if.ub_addr = '0;
                u_gnt_rd_req0_if.src     = 2'b00;
            end
        endcase
    end

    // Output port 1
    always_comb begin
        u_gnt_rd_req1_if.vld = grant1_vld;
        case (grant1_sel)
            2'd0: begin
                u_gnt_rd_req1_if.ub_addr = u_arb_normal_rd_req_if.ub_addr;
                u_gnt_rd_req1_if.src     = u_arb_normal_rd_req_if.src;
            end
            2'd1: begin
                u_gnt_rd_req1_if.ub_addr = u_arb_atomic_rd_req_if.ub_addr;
                u_gnt_rd_req1_if.src     = u_arb_atomic_rd_req_if.src;
            end
            2'd2: begin
                u_gnt_rd_req1_if.ub_addr = u_ldma_rd_req_if.ub_addr;
                u_gnt_rd_req1_if.src     = u_ldma_rd_req_if.src;
            end
            default: begin
                u_gnt_rd_req1_if.ub_addr = '0;
                u_gnt_rd_req1_if.src     = 2'b00;
            end
        endcase
    end

    // Backpressure ready signals
    logic rdy0_for_aru, rdy0_for_atomic, rdy0_for_ldma;
    logic rdy1_for_aru, rdy1_for_atomic, rdy1_for_ldma;

    assign rdy0_for_aru               = (grant0_sel == 2'd0) && grant0_vld && u_gnt_rd_req0_if.rdy;
    assign rdy0_for_atomic            = (grant0_sel == 2'd1) && grant0_vld && u_gnt_rd_req0_if.rdy;
    assign rdy0_for_ldma              = (grant0_sel == 2'd2) && grant0_vld && u_gnt_rd_req0_if.rdy;

    assign rdy1_for_aru               = (grant1_sel == 2'd0) && grant1_vld && u_gnt_rd_req1_if.rdy;
    assign rdy1_for_atomic            = (grant1_sel == 2'd1) && grant1_vld && u_gnt_rd_req1_if.rdy;
    assign rdy1_for_ldma              = (grant1_sel == 2'd2) && grant1_vld && u_gnt_rd_req1_if.rdy;

    assign u_arb_normal_rd_req_if.rdy = rdy0_for_aru | rdy1_for_aru;
    assign u_arb_atomic_rd_req_if.rdy = rdy0_for_atomic | rdy1_for_atomic;
    assign u_ldma_rd_req_if.rdy       = rdy0_for_ldma | rdy1_for_ldma;

endmodule
